package advertising

import (
	"context"
	"device-admin/config/mysql"
	"device-admin/internal/app/grpc/client"
	"device-admin/internal/app/grpc/protoc/advertisingc"
	"device-admin/internal/app/grpc/service/terminal"
	"device-admin/internal/models"
	"fmt"
	"strings"

	"device-admin/internal/app/web/service/device"

	"192.168.1.75/go-pkg/errorx"
	"192.168.1.75/go-pkg/logx"
)

type PublishSchedule struct{}

// 投放计划终止
func (PublishSchedule) PublishScheduleEnd(ctx context.Context, params *advertisingc.PublishScheduleEndReq) (err error) {
	cli, connErr := client.GetAdvertisingClient()
	if connErr != nil {
		err = errorx.New("广告系统连接错误", -1)
		return
	}
	rsp, rspErr := cli.PublishScheduleEnd(ctx, params)
	if rspErr != nil || rsp.Code != 0 {
		return errorx.New(rsp.Msg, int(rsp.Code))
	}
	logx.Info(context.Background(), "GetPublishSchedule in PublishScheduleEnd:"+rsp.Msg)
	terminal.GetPublishSchedule(rsp.Msg, true, "PublishScheduleEnd")
	return
}

// 投放计划列表
func (PublishSchedule) PublishScheduleList(ctx context.Context, params *advertisingc.PublishScheduleListReq) (
	data []*advertisingc.PublishScheduleListRsp_Data_ScheduleList, count int64, err error) {
	cli, connErr := client.GetAdvertisingClient()
	if connErr != nil {
		err = errorx.New("广告系统连接错误", -1)
		return
	}
	rsp, rspErr := cli.PublishScheduleList(ctx, params)
	if rspErr != nil {
		if rsp != nil {
			return data, count, errorx.New(fmt.Sprintf("查询广告投放计划列表错误: %s, %s", rspErr.Error(), rsp.Msg), int(rsp.Code))
		} else {
			return data, count, errorx.New(fmt.Sprintf("查询广告投放计划列表错误: %s", rspErr.Error()), -1)
		}
	}

	if rsp == nil {
		return data, count, errorx.New("查询广告投放计划列表返回空", -1)
	}

	if rsp.Code != 0 {
		return data, count, errorx.New(rsp.Msg, int(rsp.Code))
	}

	if rsp.Data.List == nil {
		rsp.Data.List = []*advertisingc.PublishScheduleListRsp_Data_ScheduleList{}
	}
	var RobotIDList = []string{}
	for _, v := range rsp.Data.List {
		RobotIDList = append(RobotIDList, v.Devices...)
	}
	var DeviceLocationList = []struct {
		RobotID    string `json:"robot_id"`
		LocationID string `json:"location_id"`
	}{}
	mysql.NewDB().Model(&models.Device{}).
		Where("robot_id in (?)", RobotIDList).
		Select("robot_id,location_id").
		Find(&DeviceLocationList)
	var RobotLocationMap = make(map[string]string)
	for _, v := range DeviceLocationList {
		RobotLocationMap[v.RobotID] = v.LocationID
	}
	for k, v := range rsp.Data.List {
		rsp.Data.List[k].DeviceLocation = ""
		deviceLocationMap := make(map[string]string)
		deviceLocations := []string{}
		for _, robot := range v.Devices {
			if locationID, ok := RobotLocationMap[robot]; ok {
				if _, ok := deviceLocationMap[locationID]; !ok { // location去重
					deviceLocationMap[locationID] = locationID
					deviceLocations = append(deviceLocations, locationID)
				}
			}
		}
		rsp.Data.List[k].DeviceLocation = strings.Join(deviceLocations, ",")
	}
	return rsp.Data.List, rsp.Data.Count, nil
}

// 投放计划详情
func (PublishSchedule) PublishScheduleDetail(ctx context.Context, params *advertisingc.PublishScheduleDetailReq) (
	data *advertisingc.PublishScheduleDetailRsp_PublishScheduleDetail, err error) {
	cli, connErr := client.GetAdvertisingClient()
	if connErr != nil {
		err = errorx.New("广告系统连接错误", -1)
		return
	}
	rsp, rspErr := cli.PublishScheduleDetail(ctx, params)
	if rspErr != nil || rsp.Code != 0 {
		return data, errorx.New(rsp.Msg, int(rsp.Code))
	}

	if rsp.Data == nil {
		rsp.Data = &advertisingc.PublishScheduleDetailRsp_PublishScheduleDetail{}
	}
	return rsp.Data, nil
}

type DeviceLFPInfo struct {
	RobotID      string `json:"robot_id"`
	LocationName string `json:"location_name"`
	LocationID   string `json:"location_id"`
	FloorName    string `json:"floor_name"`
	FloorID      string `json:"floor_id"`
	PositionName string `json:"position_name"`
	PositionID   string `json:"position_id"`
	OpeningHours string `json:"opening_hours"`
}

type PublishScheduleDetailOrderInfoRsp struct {
	Id             string                                               `json:"id,omitempty"`
	Name           string                                               `json:"name,omitempty"`
	Position       int32                                                `json:"position,omitempty"`
	StartTime      int64                                                `json:"start_time,omitempty"`
	EndTime        int64                                                `json:"end_time,omitempty"`
	Duration       int64                                                `json:"duration,omitempty"`
	Details        string                                               `json:"details,omitempty"`
	Status         int32                                                `json:"status,omitempty"`
	DistrictId     string                                               `json:"district_id,omitempty"`
	LocationId     string                                               `json:"location_id,omitempty"`
	MerchantId     string                                               `json:"merchant_id,omitempty"`
	MerchantName   string                                               `json:"merchant_name,omitempty"`
	CreateUser     string                                               `json:"create_user,omitempty"`
	CreateUsername string                                               `json:"create_username,omitempty"`
	CreatedAt      int64                                                `json:"created_at,omitempty"`
	DeletedAt      int64                                                `json:"deleted_at,omitempty"`
	Orientation    int32                                                `json:"orientation,omitempty"`
	PublishType    int32                                                `json:"publish_type,omitempty"`
	DeviceLFPInfo  []DeviceLFPInfo                                      `json:"device_lfp_info,omitempty"`
	Materials      []*advertisingc.SPublishScheduleDetailOrderInfoRsp_Data_Materials `json:"materials,omitempty"`
	DetailsShow    int32                                                `json:"details_show,omitempty"`
	PublishCount   int64                                                `json:"publish_count,omitempty"`
	Gender         string                                               `json:"gender,omitempty"`
	Age            string                                               `json:"age,omitempty"`
	Tag            string                                               `json:"tag,omitempty"`
	CustomName      string                                              `json:"custom_name,omitempty"`
	PhoneNumber     string                                              `json:"phone_number,omitempty"`
	StartAt         int64                                               `json:"start_at,omitempty"`
	EndAt           int64                                               `json:"end_at,omitempty"`
	Remark          string                                              `json:"remark,omitempty"`
	Openid          string                                              `json:"openid,omitempty"`
	AdvertisementId string                                              `json:"advertisement_id,omitempty"`
	PayAmount       float32                                             `json:"pay_amount,omitempty"`
	PaidAmount      float32                                             `json:"paid_amount,omitempty"`
	PaidId          string                                              `json:"paid_id,omitempty"`
	DiscountAmount  float32                                             `json:"discount_amount,omitempty"`
	OrderId         string                                              `json:"order_id,omitempty"`
	Platform        int32                                              `json:"platform,omitempty"`
	PayStatus       int32                                              `json:"pay_status,omitempty"`
	OutTradeNo      string                                              `json:"out_trade_no,omitempty"`
}

// 投放计划列表
func (PublishSchedule) PublishScheduleListOrderInfo(ctx context.Context, params *advertisingc.SPublishScheduleListOrderInfoReq) (
	data []*advertisingc.SPublishScheduleListOrderInfoRsp_Data_Item, count int64, err error) {
	cli, connErr := client.GetAdvertisingClient()
	if connErr != nil {
		err = errorx.New("广告系统连接错误", -1)
		return
	}
	rsp, rspErr := cli.ScheduleListOrderInfo(ctx, params)
	if rspErr != nil {
		if rsp != nil {
			return data, count, errorx.New(fmt.Sprintf("查询广告投放计划列表错误: %s, %s", rspErr.Error(), rsp.Msg), int(rsp.Code))
		} else {
			return data, count, errorx.New(fmt.Sprintf("查询广告投放计划列表错误: %s", rspErr.Error()), -1)
		}
	}

	if rsp == nil {
		return data, count, errorx.New("查询广告投放计划列表返回空", -1)
	}

	if rsp.Code != 0 {
		return data, count, errorx.New(rsp.Msg, int(rsp.Code))
	}

	if rsp.Data.List == nil {
		rsp.Data.List = []*advertisingc.SPublishScheduleListOrderInfoRsp_Data_Item{}
	}
	var RobotIDList = []string{}
	for _, v := range rsp.Data.List {
		RobotIDList = append(RobotIDList, v.Devices...)
	}
	var DeviceLocationList = []struct {
		RobotID    string `json:"robot_id"`
		LocationID string `json:"location_id"`
	}{}
	mysql.NewDB().Model(&models.Device{}).
		Where("robot_id in (?)", RobotIDList).
		Select("robot_id,location_id").
		Find(&DeviceLocationList)
	var RobotLocationMap = make(map[string]string)
	for _, v := range DeviceLocationList {
		RobotLocationMap[v.RobotID] = v.LocationID
	}
	for k, v := range rsp.Data.List {
		rsp.Data.List[k].DeviceLocation = ""
		deviceLocationMap := make(map[string]string)
		deviceLocations := []string{}
		for _, robot := range v.Devices {
			if locationID, ok := RobotLocationMap[robot]; ok {
				if _, ok := deviceLocationMap[locationID]; !ok { // location去重
					deviceLocationMap[locationID] = locationID
					deviceLocations = append(deviceLocations, locationID)
				}
			}
		}
		rsp.Data.List[k].DeviceLocation = strings.Join(deviceLocations, ",")
	}
	return rsp.Data.List, rsp.Data.Count, nil
}

// 投放计划详情
func (PublishSchedule) PublishScheduleDetailOrderInfo(ctx context.Context, params *advertisingc.SPublishScheduleDetailOrderInfoReq) (
	data *PublishScheduleDetailOrderInfoRsp, err error) {
	cli, connErr := client.GetAdvertisingClient()
	if connErr != nil {
		err = errorx.New("广告系统连接错误", -1)
		return
	}

	rsp, rspErr := cli.ScheduleDetailOrderInfo(ctx, params)
	if rspErr != nil || rsp.Code != 0 {
		return data, errorx.New(rsp.Msg, int(rsp.Code))
	}

	if rsp.Data == nil {
		rsp.Data = &advertisingc.SPublishScheduleDetailOrderInfoRsp_Data{}
	}

	// 构建 DeviceLFPInfo 数组
	deviceLFPInfoList := []DeviceLFPInfo{}
	for _, v := range rsp.Data.Devices {
		deviceInfo, _ := device.DeviceDetail("", "", v)
		deviceLFPInfo := DeviceLFPInfo{
			RobotID:      v,
			LocationName: deviceInfo.LocationName,
			LocationID:   deviceInfo.LocationID,
			FloorName:    deviceInfo.FloorName,
			FloorID:      deviceInfo.FloorID,
			PositionName: deviceInfo.PositionName,
			PositionID:   deviceInfo.PositionID,
			OpeningHours: deviceInfo.OpeningHours,
		}
		deviceLFPInfoList = append(deviceLFPInfoList, deviceLFPInfo)
	}

	// 构建新的返回结构，去掉 deviceCount, deviceIDs, device_location，并将 devices 替换为 deviceLFPInfo
	result := &PublishScheduleDetailOrderInfoRsp{
		Id:             rsp.Data.Id,
		Name:           rsp.Data.Name,
		Position:       rsp.Data.Position,
		StartTime:      rsp.Data.StartTime,
		EndTime:        rsp.Data.EndTime,
		Duration:       rsp.Data.Duration,
		Details:        rsp.Data.Details,
		Status:         rsp.Data.Status,
		DistrictId:     rsp.Data.DistrictId,
		LocationId:     rsp.Data.LocationId,
		MerchantId:     rsp.Data.MerchantId,
		MerchantName:   rsp.Data.MerchantName,
		CreateUser:     rsp.Data.CreateUser,
		CreateUsername: rsp.Data.CreateUsername,
		CreatedAt:      rsp.Data.CreatedAt,
		DeletedAt:      rsp.Data.DeletedAt,
		Orientation:    rsp.Data.Orientation,
		PublishType:    rsp.Data.PublishType,
		DeviceLFPInfo:  deviceLFPInfoList,
		Materials:      rsp.Data.Materials,
		DetailsShow:    rsp.Data.DetailsShow,
		PublishCount:   rsp.Data.PublishCount,
		Gender:         rsp.Data.Gender,
		Age:            rsp.Data.Age,
		Tag:            rsp.Data.Tag,
		CustomName:     rsp.Data.CustomName,
		PhoneNumber:    rsp.Data.PhoneNumber,
		StartAt:        rsp.Data.StartAt,
		EndAt:          rsp.Data.EndAt,
		Remark:         rsp.Data.Remark,
		Openid:         rsp.Data.Openid,
		AdvertisementId: rsp.Data.AdvertisementId,
		PayAmount:      rsp.Data.PayAmount,
		PaidAmount:     rsp.Data.PaidAmount,
		PaidId:         rsp.Data.PaidId,
		DiscountAmount: rsp.Data.DiscountAmount,
		OrderId:        rsp.Data.OrderId,
		Platform:       rsp.Data.Platform,
		PayStatus:      rsp.Data.PayStatus,
		OutTradeNo:     rsp.Data.OutTradeNo,
	}

	return result, nil
}

// 投放计划编辑
func (PublishSchedule) PublishScheduleSave(ctx context.Context, params *advertisingc.PublishScheduleSaveReq) (err error) {
	cli, connErr := client.GetAdvertisingClient()
	if connErr != nil {
		err = errorx.New("广告系统连接错误", -1)
		return
	}
	rsp, rspErr := cli.PublishScheduleSave(ctx, params)
	if rspErr != nil || rsp.Code != 0 {
		return errorx.New(rsp.Msg, int(rsp.Code))
	}

	logx.Info(context.Background(), "GetPublishSchedule in PublishScheduleSave:"+rsp.Devices)
	terminal.GetPublishSchedule(rsp.Devices, true, "PublishScheduleSave")
	return
}

// 投放计划审核
func (PublishSchedule) PublishScheduleAudit(ctx context.Context, params *advertisingc.PublishScheduleAuditReq) (err error) {
	cli, connErr := client.GetAdvertisingClient()
	if connErr != nil {
		err = errorx.New("广告系统连接错误", -1)
		return
	}
	rsp, rspErr := cli.PublishScheduleAudit(ctx, params)
	if rspErr != nil || rsp.Code != 0 {
		return errorx.New(rsp.Msg, int(rsp.Code))
	}

	return
}

// 投放计划审核列表
func (PublishSchedule) PublishScheduleAuditLogList(ctx context.Context, params *advertisingc.PublishScheduleAuditLogListReq) (
	data []*advertisingc.PublishScheduleAuditLogListRsp_Data_PublishScheduleAuditLogList, count int64, err error) {
	cli, connErr := client.GetAdvertisingClient()
	if connErr != nil {
		err = errorx.New("广告系统连接错误", -1)
		return
	}
	rsp, rspErr := cli.PublishScheduleAuditLogList(ctx, params)
	if rspErr != nil || rsp.Code != 0 {
		return data, count, errorx.New(rsp.Msg, int(rsp.Code))
	}
	if rsp.Data.List == nil {
		rsp.Data.List = []*advertisingc.PublishScheduleAuditLogListRsp_Data_PublishScheduleAuditLogList{}
	}
	var RobotIDList = []string{}
	for _, v := range rsp.Data.List {
		RobotIDList = append(RobotIDList, v.Devices...)
	}
	var DeviceLocationList = []struct {
		RobotID    string `json:"robot_id"`
		LocationID string `json:"location_id"`
	}{}
	mysql.NewDB().Model(&models.Device{}).
		Where("robot_id in (?)", RobotIDList).
		Select("robot_id,location_id").
		Find(&DeviceLocationList)
	var RobotLocationMap = make(map[string]string)
	for _, v := range DeviceLocationList {
		RobotLocationMap[v.RobotID] = v.LocationID
	}
	for k, v := range rsp.Data.List {
		rsp.Data.List[k].DeviceLocation = ""
		for _, robot := range v.Devices {
			if _, ok := RobotLocationMap[robot]; ok {
				rsp.Data.List[k].DeviceLocation = rsp.Data.List[k].DeviceLocation + "," + RobotLocationMap[robot]
			}
		}
		rsp.Data.List[k].DeviceLocation = strings.TrimLeft(rsp.Data.List[k].DeviceLocation, ",")
	}
	return rsp.Data.List, rsp.Data.Count, nil
}

// 投放计划审核列表
func (PublishSchedule) PublishScheduleAuditLogListOrderInfo(ctx context.Context, params *advertisingc.SPublishScheduleAuditLogListOrderInfoReq) (
	data []*advertisingc.SPublishScheduleAuditLogListOrderInfoRsp_Data_PublishScheduleAuditLogList, count int64, err error) {
	cli, connErr := client.GetAdvertisingClient()
	if connErr != nil {
		err = errorx.New("广告系统连接错误", -1)
		return
	}
	rsp, rspErr := cli.ScheduleAuditLogListOrderInfo(ctx, params)
	if rspErr != nil || rsp.Code != 0 {
		return data, count, errorx.New(rsp.Msg, int(rsp.Code))
	}
	if rsp.Data.List == nil {
		rsp.Data.List = []*advertisingc.SPublishScheduleAuditLogListOrderInfoRsp_Data_PublishScheduleAuditLogList{}
	}
	var RobotIDList = []string{}
	for _, v := range rsp.Data.List {
		RobotIDList = append(RobotIDList, v.Devices...)
	}
	var DeviceLocationList = []struct {
		RobotID    string `json:"robot_id"`
		LocationID string `json:"location_id"`
	}{}
	mysql.NewDB().Model(&models.Device{}).
		Where("robot_id in (?)", RobotIDList).
		Select("robot_id,location_id").
		Find(&DeviceLocationList)
	var RobotLocationMap = make(map[string]string)
	for _, v := range DeviceLocationList {
		RobotLocationMap[v.RobotID] = v.LocationID
	}
	for k, v := range rsp.Data.List {
		rsp.Data.List[k].DeviceLocation = ""
		for _, robot := range v.Devices {
			if _, ok := RobotLocationMap[robot]; ok {
				rsp.Data.List[k].DeviceLocation = rsp.Data.List[k].DeviceLocation + "," + RobotLocationMap[robot]
			}
		}
		rsp.Data.List[k].DeviceLocation = strings.TrimLeft(rsp.Data.List[k].DeviceLocation, ",")
	}
	return rsp.Data.List, rsp.Data.Count, nil
}
